home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programmierung
/
Power-Programmierung (Tewi)(1994).iso
/
magazine
/
msysjour
/
vol06
/
01
/
kermit
/
wnkfns.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-12-31
|
36KB
|
1,530 lines
/*
* WNKFNS.C
*
* Windows Kermit protocol support functions
*
* Copyright (c) 1990 by
* William S. Hall
* 3665 Benton Street, #66
* Santa Clara, CA 95051
*
*/
/* The file is large, so these defines reduce the size of
* the symbol table generated by windows.h
*/
#define NOGDICAPMASKS - CC_*, LC_*, PC_*, CP_*, TC_*, RC_
#define NOVIRTUALKEYCODES - VK_*
#define NOWINMESSAGES - WM_*, EM_*, LB_*, CB_*
#define NOWINSTYLES - WS_*, CS_*, ES_*, LBS_*, SBS_*, CBS_*
#define NOSYSMETRICS - SM_*
// #define NOMENUS - MF_*
#define NOICONS - IDI_*
#define NOKEYSTATES - MK_*
#define NOSYSCOMMANDS - SC_*
#define NORASTEROPS - Binary and Tertiary raster ops
// #define NOSHOWWINDOW - SW_*
#define OEMRESOURCE - OEM Resource values
#define NOATOM - Atom Manager routines
#define NOCLIPBOARD - Clipboard routines
#define NOCOLOR - Screen colors
// #define NOCTLMGR - Control and Dialog routines
// #define NODRAWTEXT - DrawText() and DT_*
// #define NOGDI - All GDI defines and routines
// #define NOKERNEL - All KERNEL defines and routines
// #define NOUSER - All USER defines and routines
// #define NOMB - MB_* and MessageBox()
// #define NOMEMMGR - GMEM_*, LMEM_*, GHND, LHND, associated routines
#define NOMETAFILE - typedef METAFILEPICT
#define NOMINMAX - Macros min(a,b) and max(a,b)
#define NOMSG - typedef MSG and associated routines
// #define NOOPENFILE - OpenFile(), OemToAnsi, AnsiToOem, and OF_*
#define NOSCROLL - SB_* and scrolling routines
#define NOSOUND - Sound driver routines
#define NOTEXTMETRIC - typedef TEXTMETRIC and associated routines
#define NOWH - SetWindowsHook and WH_*
#define NOWINOFFSETS - GWL_*, GCL_*, associated routines
// #define NOCOMM - COMM driver routines
#define NOKANJI - Kanji support stuff.
#define NOHELP - Help engine interface.
#define NOPROFILER - Profiler interface.
#define NODEFERWINDOWPOS - DeferWindowPos routines
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <io.h>
#include <sys\types.h>
#include <sys\stat.h>
#include "ascii.h"
#include "wnkerm.h"
#include "wnkdlg.h"
/* local function declarations */
static short NEAR krmWriteComm(int cid, BYTE *buf, int len);
static short NEAR krm_spack(char type, int n, int len, BYTE *data);
static void NEAR krm_errpkt(int msgnum);
static void NEAR krmSet8BitQuote(register BYTE sq);
static void NEAR krm_nak(void);
static void NEAR krmSetMenus(BOOL mode);
static void NEAR krmUpdateXferBox(WORD id, char *str);
static void NEAR krm_nxtpkt(void);
static int NEAR krm_decode(BYTE outbuf[], BYTE inbuf[], int *len);
static int NEAR krm_getpacket(register BYTE *str, register int len);
static WORD NEAR krm_chk1(WORD);
static WORD NEAR krm_chksum(BYTE *p, WORD init);
static DWORD NEAR krm_chksum3(BYTE *p, DWORD init);
static HANDLE NEAR krmOpenReceiveFile(BYTE *inbuf);
BOOL FAR PASCAL krmHideChildren(HWND hWnd, LONG lParam);
/*
* krm_getnextfile
*
* Parse the string of file names for the next one to send.
* The names themselves are delimited by a space.
*/
char * NEAR krm_getnextfile(BOOL first)
{
char *type;
if (Kermit.abort == KRM_BATCHABORT) {
Kermit.abort = 0;
return (char *)NULL;
}
type = (first ? Kermit.pFilelist : NULL);
return strtok(type, " ");
}
/*
* krm_err
*
* Send an error packet to remote Kermit
* and exit protocol with a message to user.
*/
void NEAR krm_err(int ref)
{
krm_errpkt(ref);
krm_tend(ref);
}
/*
* krm_sinit
*
* Send an init packet to remote Kermit
*/
int NEAR krm_sinit(void)
{
BYTE data[40];
register int i = krm_rpar(data);
return (krm_spack('S', Kermit.seq, i, data));
}
/*
* krm_sfile
*
* Send file name packet to remote Kermit
*/
int NEAR krm_sfile(void)
{
BYTE buf[KRM_MAXDATALEN + 1];
register int outlen;
int inlen;
int result;
struct stat fdata;
if ((Kermit.hFile = OpenFile((LPSTR)Kermit.pFile,
(OFSTRUCT FAR *)&Kermit.fstruct, OF_READ)) != -1) {
stat(Kermit.fstruct.szPathName, &fdata);
Kermit.filesize = fdata.st_size ? fdata.st_size : Kermit.filesize;
Kermit.bytesmoved = 0;
if (KermParams.verbose) {
krmUpdateXferBox(IDD_KRM_FILENAME,
(strrchr(Kermit.fstruct.szPathName,'\\') + 1));
krmUpdateXferBox(IDD_KRM_BYTESMOVED,
ultoa(Kermit.bytesmoved,buf,10));
krmUpdateXferBox(IDD_KRM_PERCENTAGE,itoa(0, buf, 10));
}
Kermit.maxsenddatalen = krm_sndinit.maxpktsize - 2 - Kermit.bctu;
inlen = strlen(Kermit.pFile);
outlen = krm_encode(buf, Kermit.pFile, Kermit.maxsenddatalen, &inlen);
krm_nxtpkt();
result = krm_spack('F',Kermit.seq, outlen, buf);
if (result < 0) {
krm_rclose(FALSE);
return result;
}
}
return (Kermit.hFile);
}
/*
* krm_sdata
*
* Send encoded data packet to remote Kermit
*/
int NEAR krm_sdata(void)
{
BYTE sbuf[KRM_MAXDATALEN + 1];
BYTE rbuf[KRM_MAXDATALEN + 1];
register int len;
register int numread;
int numrem = 0;
int result;
BYTE *sptr;
int numcoded = 0;
int maxlen = Kermit.maxsenddatalen;
for (sptr = sbuf; (numrem == 0) && (numcoded < maxlen);
sptr += len, maxlen -= len) {
if ((numread = read(Kermit.hFile, rbuf, sizeof(rbuf) - 1)) > 0) {
numrem = numread;
numcoded += len = krm_encode(sptr, rbuf, maxlen, &numrem);
Kermit.bytesmoved = lseek(Kermit.hFile, -(LONG)numrem, SEEK_CUR);
}
else
break;
}
if ((numread >= 0) && (numcoded > 0)) {
krm_nxtpkt();
result = krm_spack('D', Kermit.seq, numcoded, sbuf);
if (result > 0) {
if (KermParams.verbose) {
krmUpdateXferBox(IDD_KRM_BYTESMOVED,
ultoa(Kermit.bytesmoved,sbuf,10));
krmUpdateXferBox(IDD_KRM_PERCENTAGE,
ultoa(Kermit.bytesmoved * 100 / Kermit.filesize, sbuf, 10));
}
}
return result;
}
return numread;
}
/*
* krm_seof
*
* Send end of file packet to remote Kermit
*/
int NEAR krm_seof(char *s)
{
if (krm_rclose(FALSE)) {
krm_nxtpkt();
return (krm_spack('Z', Kermit.seq, strlen(s), s));
}
return (-1);
}
/*
* krm_seot
*
* Send end of transmission (break) packet to remote Kermit
*/
int NEAR krm_seot(void)
{
krm_nxtpkt();
return (krm_spack('B', Kermit.seq, 0, ""));
}
/*
* krm_encode
*
* Encode a buffer quoting control characters,
* adding run length encoding and eight bit
* quoting if requested, while packing buffer to its maximum.
*/
int NEAR krm_encode(BYTE *outbuf, BYTE *inbuf, int maxlen, int *inlen)
{
register int i, j;
BYTE t, t7;
BYTE b8;
int rpt = 0;
int back = 1;
int extra = 0;
for (i = 0, j = 0; (i < maxlen) && (j < *inlen); ) {
t = inbuf[j++];
t7 = t & (BYTE)0x7f;
b8 = t & (BYTE)0x80;
if (Kermit.rptflag) {
for (rpt = 0; (rpt < 93) && (j < *inlen); rpt++, j++)
if (t != inbuf[j])
break;
if (rpt == 1) {
j -= 1;
rpt = 0;
}
back = 1 + rpt;
extra = rpt ? 2 : 0;
if (rpt > 1)
rpt += 1;
}
if ((t7 < SP) || (t7 == DEL)) {
if (Kermit.ebqflag && b8) {
if (i < (maxlen - 2 - extra)) {
if (rpt) {
outbuf[i++] = krm_sndinit.rpquote;
outbuf[i++] = (BYTE)tochar(rpt);
}
outbuf[i++] = krm_sndinit.ebquote;
outbuf[i++] = krm_sndinit.quote;
outbuf[i++] = (BYTE)ctl(t7);
}
else {
j -= back;
break;
}
}
else {
if (i < (maxlen - 1 - extra)) {
if (rpt) {
outbuf[i++] = krm_sndinit.rpquote;
outbuf[i++] = (BYTE)tochar(rpt);
}
outbuf[i++] = krm_sndinit.quote;
outbuf[i++] = (BYTE)ctl(t);
}
else {
j -= back;
break;
}
}
}
else if (t7 == krm_sndinit.rpquote) {
if (Kermit.rptflag) {
if (Kermit.ebqflag) {
if (b8) {
if (i < (maxlen - 2 - extra)) {
if (rpt) {
outbuf[i++] = krm_sndinit.rpquote;
outbuf[i++] = (BYTE)tochar(rpt);
}
outbuf[i++] = krm_sndinit.ebquote;
outbuf[i++] = krm_sndinit.quote;
outbuf[i++] = t7;
}
else {
j -= back;
break;
}
}
else {
if (i < (maxlen - 1 - extra)) {
if (rpt) {
outbuf[i++] = krm_sndinit.rpquote;
outbuf[i++] = (BYTE)tochar(rpt);
}
outbuf[i++] = krm_sndinit.quote;
outbuf[i++] = t7;
}
else {
j -= back;
break;
}
}
}
else {
if (i < (maxlen - 1 - extra)) {
if (rpt) {
outbuf[i++] = krm_sndinit.rpquote;
outbuf[i++] = (BYTE)tochar(rpt);
}
outbuf[i++] = krm_sndinit.quote;
outbuf[i++] = t;
}
else {
j -= back;
break;
}
}
}
else {
if (Kermit.ebqflag && b8) {
if (i < (maxlen - 1 - extra)) {
outbuf[i++] = krm_sndinit.ebquote;
outbuf[i++] = t7;
}
else {
j -= back;
break;
}
}
else {
if (i < (maxlen - extra)) {
outbuf[i++] = t;
}
else {
j -= back;
break;
}
}
}
}
else if (t7 == krm_sndinit.ebquote) {
if (Kermit.ebqflag) {
if (b8) {
if (i < (maxlen - 2 - extra)) {
if (rpt) {
outbuf[i++] = krm_sndinit.rpquote;
outbuf[i++] = (BYTE)tochar(rpt);
}
outbuf[i++] = krm_sndinit.ebquote;
outbuf[i++] = krm_sndinit.quote;
outbuf[i++] = t7;
}
else {
j -= back;
break;
}
}
else {
if (i < (maxlen - 1 - extra)) {
if (rpt) {
outbuf[i++] = krm_sndinit.rpquote;
outbuf[i++] = (BYTE)tochar(rpt);
}
outbuf[i++] = krm_sndinit.quote;
outbuf[i++] = t7;
}
else {
j -= back;
break;
}
}
}
else {
if (i < (maxlen - extra)) {
if (rpt) {
outbuf[i++] = krm_sndinit.rpquote;
outbuf[i++] = (BYTE)tochar(rpt);
}
outbuf[i++] = t;
}
else {
j -= back;
break;
}
}
}
else if (t7 == krm_sndinit.quote) {
if (Kermit.ebqflag && b8) {
if (i < (maxlen - 2 - extra)) {
if (rpt) {
outbuf[i++] = krm_sndinit.rpquote;
outbuf[i++] = (BYTE)tochar(rpt);
}
outbuf[i++] = krm_sndinit.ebquote;
outbuf[i++] = krm_sndinit.quote;
outbuf[i++] = t7;
}
else {
j -= back;
break;
}
}
else {
if (i < (maxlen - 1 - extra)) {
if (rpt) {
outbuf[i++] = krm_sndinit.rpquote;
outbuf[i++] = (BYTE)tochar(rpt);
}
outbuf[i++] = krm_sndinit.quote;
outbuf[i++] = t;
}
else {
j -= back;
break;
}
}
}
else {
if (Kermit.ebqflag && b8) {
if (i < (maxlen - 1 - extra)) {
if (rpt) {
outbuf[i++] = krm_sndinit.rpquote;
outbuf[i++] = (BYTE)tochar(rpt);
}
outbuf[i++] = krm_sndinit.ebquote;
outbuf[i++] = t7;
}
else {
j -= back;
break;
}
}
else {
if (i < (maxlen - extra)) {
if (rpt) {
outbuf[i++] = krm_sndinit.rpquote;
outbuf[i++] = (BYTE)tochar(rpt);
}
outbuf[i++] = t;
}
else {
j -= back;
break;
}
}
}
}
outbuf[i] = NUL;
*inlen -= j;
return i;
}
/*
* krm_rcvfile
*
* Get a file name from remote Kermit and open
* it for writing.
*/
BOOL NEAR krm_rcvfil(void)
{
BYTE buf[KRM_MAXPACKETSIZE + 1];
int len = krm_rcvpkt.len;
krm_decode(buf, krm_rcvpkt.data, &len);
if (KermParams.verbose)
krmUpdateXferBox(IDD_KRM_FILENAME, buf);
if ((Kermit.hFile = krmOpenReceiveFile(buf)) != -1) {
Kermit.bytesmoved = 0;
Kermit.pFile = strrchr(Kermit.fstruct.szPathName,'\\') + 1;
if (KermParams.verbose) {
krmUpdateXferBox(IDD_KRM_SAVENAME, Kermit.pFile);
krmUpdateXferBox(IDD_KRM_BYTESMOVED,
ultoa(Kermit.bytesmoved, buf, 10));
}
return TRUE;
}
return FALSE;
}
/*
* krm_rcvdata
*
* Get a data packet from remote Kermit and save
* to a file
*/
BOOL NEAR krm_rcvdata(void)
{
BYTE buf[KRM_MAXPACKETSIZE + 1];
register int outlen;
int startlen, inlen;
register BYTE *ptr;
for (ptr = krm_rcvpkt.data, startlen = inlen = krm_rcvpkt.len;
inlen > 0; ptr += (startlen - inlen), startlen = inlen) {
outlen = krm_decode(buf, ptr, &inlen);
if (write(Kermit.hFile, buf, outlen) == -1)
return FALSE;
Kermit.bytesmoved += (DWORD)outlen;
}
if (KermParams.verbose)
krmUpdateXferBox(IDD_KRM_BYTESMOVED, ultoa(Kermit.bytesmoved, buf, 10));
return TRUE;
}
/*
* krm_rclose
*
* Close a file under normal or error conditions
* deleting a partially received file if necessary.
*/
BOOL NEAR krm_rclose(BOOL remove)
{
if (Kermit.hFile > 0) {
if (close(Kermit.hFile) == 0) {
Kermit.hFile = 0;
if (remove &&
KermParams.DiscardPartialFile &&
(Kermit.mode == IDM_KRM_RECEIVE)) {
unlink(Kermit.fstruct.szPathName);
}
return TRUE;
}
}
else if (Kermit.hFile == 0)
return TRUE;
return FALSE;
}
/*
* krm_decode
*
* Decode control, eight-bit, and repeat character quote characters
* in a received data packet.
*/
static int NEAR krm_decode(BYTE outbuf[], BYTE inbuf[], int *len)
{
BYTE a, a7;
register int i,j;
BYTE bitset;
int rpt;
for (i = 0, j = 0; (j < *len) && (i < KRM_MAXPACKETSIZE); ) {
rpt = 1;
a = inbuf[j++];
if (Kermit.rptflag) {
if (a == krm_rcvinit.rpquote) {
rpt = unchar(inbuf[j++]);
if (rpt <= (KRM_MAXPACKETSIZE - i))
a = inbuf[j++];
else {
j -= 2;
break;
}
}
}
bitset = 0;
if (Kermit.ebqflag) {
if (a == krm_rcvinit.ebquote) {
a = inbuf[j++];
bitset = 0x80;
}
}
if (a == krm_rcvinit.quote) {
a = inbuf[j++];
a7 = a & (BYTE)0x7f;
if ((a7 >= '?') && ( a7 <= '_'))
a = (BYTE)ctl(a);
}
a |= bitset;
for ( ; rpt > 0; rpt--)
outbuf[i++] = a;
}
*len -= j;
outbuf[i] = NUL;
return i;
}
/*
* krm_rpack
*
* Read and call routines to build an incoming packet.
*/
int NEAR krm_rpack(void)
{
register int type;
switch(krm_rcvpkt.state) {
case PS_START:
if (KermParams.Timer)
SetTimer(Kermit.hWnd, KRM_WAITPACKET,
krm_sndinit.timeout * 1000, Kermit.fpTimer);
krm_rcvpkt.state += 1;
default:
if (*krmBuflen)
*krmBuflen = krm_getpacket(krmBufptr, *krmBuflen);
if (krm_rcvpkt.state < PS_DONE) {
type = '$';
break;
}
case PS_DONE:
krm_rcvpkt.state = PS_START;
if (KermParams.Timer)
KillTimer(Kermit.hWnd, KRM_WAITPACKET);
type = krm_rcvpkt.type;
}
return type;
}
/*
* krm_getpacket
*
* Attempt to build as much as possible of a complete incoming
* packet.
*/
static int NEAR krm_getpacket(register BYTE *str, register int len)
{
static BYTE buf[5];
WORD chk;
DWORD chk3;
for ( ; len > 0; len--, str++) {
switch(krm_rcvpkt.state) {
case PS_SYNCH:
if (*str == krm_rcvinit.mark) {
krm_rcvpkt.data_count = 0;
krm_rcvpkt.chk_count = 0;
krm_rcvpkt.data[0] = 0;
krm_rcvpkt.state++;
}
break;
case PS_LEN:
krm_rcvpkt.len = unchar(*str) - 2 - Kermit.bctu;
if (krm_rcvpkt.len > KRM_MAXDATALEN)
krm_rcvpkt.len = KRM_MAXDATALEN;
buf[0] = *str;
krm_rcvpkt.state++;
break;
case PS_NUM:
krm_rcvpkt.seq = unchar(*str);
buf[1] = *str;
krm_rcvpkt.state++;
break;
case PS_TYPE:
krm_rcvpkt.type = *str;
buf[2] = *str;
buf[3] = 0;
if (krm_rcvpkt.len)
krm_rcvpkt.state++;
else
krm_rcvpkt.state = PS_CHK;
break;
case PS_DATA:
if (krm_rcvpkt.data_count < krm_rcvpkt.len) {
krm_rcvpkt.data[krm_rcvpkt.data_count++] = *str;
break;
}
else {
krm_rcvpkt.data[krm_rcvpkt.data_count] = NUL;
krm_rcvpkt.state++;
/* fall thru */
}
case PS_CHK:
if (krm_rcvpkt.chk_count < Kermit.bctu) {
krm_rcvpkt.rchksum[krm_rcvpkt.chk_count++] = *str;
break;
}
switch(Kermit.bctu) {
case 1:
default:
chk = krm_chk1(krm_chksum(krm_rcvpkt.data,
krm_chksum(buf,0)));
if (chk != (WORD)unchar(krm_rcvpkt.rchksum[0]))
krm_rcvpkt.type = 'Q';
break;
case 2:
chk = ((WORD)unchar(krm_rcvpkt.rchksum[0]) << 6) |
(WORD)unchar(krm_rcvpkt.rchksum[1]);
if (chk != krm_chksum(krm_rcvpkt.data,
krm_chksum(buf,0)))
krm_rcvpkt.type = 'Q';
break;
case 3:
chk3 = ((WORD)unchar(krm_rcvpkt.rchksum[0]) << 12) |
((WORD)unchar(krm_rcvpkt.rchksum[1]) << 6) |
(WORD)unchar(krm_rcvpkt.rchksum[2]);
if (chk3 != krm_chksum3(krm_rcvpkt.data,
krm_chksum3(buf,0)))
krm_rcvpkt.type = 'Q';
break;
}
krm_rcvpkt.state++;
break;
case PS_DONE:
if (*str == krm_rcvinit.eol)
len--;
return len;
break;
}
}
return len;
}
/*
* krm_tinit
*
* Initialize for file transfer
*/
void NEAR krm_tinit(void)
{
DCB mydcb;
FARPROC fp;
// Get data from KermParams
Kermit.bctr = KermParams.BlockCheckType;
Kermit.bctu = 1;
// Get data from sndparams
krm_sndinit.mark = sndparams.mark;
krm_sndinit.maxpktsize = sndparams.maxpktsize;
krm_sndinit.timeout = sndparams.timeout;
krm_sndinit.padcount = sndparams.padcount;
krm_sndinit.padchar = sndparams.padchar;
krm_sndinit.eol = sndparams.eol;
krm_sndinit.quote = sndparams.quote;
// Get data from rcvparams;
krm_rcvinit.mark = rcvparams.mark;
krm_rcvinit.maxpktsize = rcvparams.maxpktsize;
krm_rcvinit.timeout = rcvparams.timeout;
krm_rcvinit.padcount = rcvparams.padcount;
krm_rcvinit.padchar = rcvparams.padchar;
krm_rcvinit.eol = rcvparams.eol;
krm_rcvinit.quote = rcvparams.quote;
// Set other values
krm_sndinit.ebquote = 'N';
krm_sndinit.rpquote = KermParams.rpquote;
// Check parity and set eight-bit request
GetCommState(*krmcid, &mydcb);
if (mydcb.ByteSize == 8)
krm_rcvinit.ebquote = 'Y';
else
krm_rcvinit.ebquote = KermParams.ebquote;
krm_rcvinit.rpquote = KermParams.rpquote;
// If verbose, prepare a dialog box to show transfer and hide child windows
if (KermParams.verbose) {
fp = MakeProcInstance((FARPROC)krmHideChildren, Kermit.hInst);
EnumChildWindows(Kermit.hWnd, fp, (LONG)SW_HIDE);
FreeProcInstance(fp);
Kermit.hWndXfer = CreateDialog(Kermit.hInst,
MAKEINTRESOURCE(DT_KRM_XFER),
Kermit.hWnd, Kermit.fpXfer);
}
else
Kermit.hWndXfer = NULL;
// If delay before first send packet, then set timer
if (KermParams.SendDelay) {
SetTimer(Kermit.hWnd, KRM_WAITSEND, KermParams.SendDelay * 1000,
Kermit.fpTimer);
Kermit.delay = TRUE;
}
// Set more parameters
krm_rcvpkt.state = PS_START;
krm_rcvpkt.seq = 0;
krm_sndpkt[0] = NUL;
Kermit.seq = 0;
Kermit.retries = 0;
Kermit.totalretries = 0;
Kermit.bytesmoved = 0L;
Kermit.packetcount = 0L;
Kermit.filesize = ULONG_MAX;
Kermit.abort = 0;
Kermit.InTransfer = TRUE;
Kermit.hFile = 0;
Kermit.hFilelist = NULL;
Kermit.pFile = NULL;
Kermit.ebqflag = FALSE;
Kermit.rptflag = FALSE;
Kermit.maxsenddatalen = krm_sndinit.maxpktsize - 5; /* worst case */
krmSetMenus(TRUE);
krmFlushQue();
}
/*
* krmSetMenus
*
* Toggle menus according to whether Kermit is starting or ending
*/
static void NEAR krmSetMenus(BOOL mode)
{
HMENU hMenu = GetMenu(Kermit.hWnd);
EnableMenuItem(hMenu, IDM_KRM_RECEIVE, mode ? MF_GRAYED : MF_ENABLED);
EnableMenuItem(hMenu, IDM_KRM_SEND, mode ? MF_GRAYED : MF_ENABLED);
EnableMenuItem(hMenu, IDM_KRM_PROTOCOL, mode ? MF_GRAYED : MF_ENABLED);
EnableMenuItem(hMenu, IDM_KRM_PACKETS, mode ? MF_GRAYED : MF_ENABLED);
EnableMenuItem(hMenu, IDM_KRM_CANCEL, mode ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(hMenu, IDM_KRM_FILEABORT, mode ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(hMenu, IDM_KRM_BATCHABORT, mode ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(hMenu, IDM_KRM_ERRORABORT, mode ? MF_ENABLED : MF_GRAYED);
}
/*
* krm_tend
*
* Terminate Kermit file transfer and clean up
*/
void NEAR krm_tend(int code)
{
FARPROC fp;
KillTimer(Kermit.hWnd, KRM_WAITPACKET);
KillTimer(Kermit.hWnd, KRM_WAITSEND);
if (Kermit.hFilelist) {
LocalUnlock(Kermit.hFilelist);
LocalFree(Kermit.hFilelist);
}
Kermit.InTransfer = FALSE;
krmSetMenus(FALSE);
if (KermParams.Bell)
MessageBeep(code);
krmShowMessage(code);
InvalidateRect(Kermit.hWnd, NULL, TRUE);
if (KermParams.verbose) {
if (IsWindow(Kermit.hWndXfer))
DestroyWindow(Kermit.hWndXfer);
fp = MakeProcInstance((FARPROC)krmHideChildren, Kermit.hInst);
EnumChildWindows(Kermit.hWnd, fp, (LONG)SW_RESTORE);
FreeProcInstance(fp);
}
}
/*
* krmShutdown
*
* Terminate Kermit and release any used resources.
* If in the middle of a tranfer, ask if user really
* wants to shut down. This function should be called
* at WM_CLOSE and WM_QUERYENDSESSION in the terminal program.
* If it returns anything but IDYES, then the terminal
* program should not terminate.
*/
int FAR krmShutdown()
{
char buf[80];
char appname[20];
int result = IDYES;
if (Kermit.InTransfer) {
LoadString(Kermit.hInst, IDS_KRM_KERMIT, appname, sizeof(appname));
LoadString(Kermit.hInst, IDS_KRM_QUIT, (LPSTR)buf, sizeof(buf));
result = MessageBox(GetFocus(),buf,appname,MB_ICONQUESTION | MB_YESNO);
if (result == IDYES) {
krm_errpkt(IDS_KRM_CANCELLED);
krm_rclose(TRUE);
KillTimer(Kermit.hWnd, KRM_WAITPACKET);
KillTimer(Kermit.hWnd, KRM_WAITSEND);
if (KermParams.verbose)
if (IsWindow(Kermit.hWndXfer))
DestroyWindow(Kermit.hWndXfer);
}
}
if (result == IDYES) {
FreeProcInstance(Kermit.fpTimer);
FreeProcInstance(Kermit.fpXfer);
}
return result;
}
/*
* krm_spack
*
* Assemble a packet for transmission
*/
short NEAR krm_spack(char type, int n, int len, BYTE *data)
{
register int i, j;
WORD chk;
DWORD chk3;
i = 0;
krm_sndpkt[i++] = krm_sndinit.mark;
krm_sndpkt[i++] = (BYTE)tochar(len + 2 + Kermit.bctu);
krm_sndpkt[i++] = (BYTE)tochar(n);
krm_sndpkt[i++] = type;
for (j = len; j > 0; j--)
krm_sndpkt[i++] = *data++;
krm_sndpkt[i] = NUL;
switch(Kermit.bctu) {
case 1:
default:
krm_sndpkt[i++] =
(BYTE)tochar(krm_chk1(krm_chksum(krm_sndpkt+1,0)));
break;
case 2:
chk = krm_chksum(krm_sndpkt+1,0);
krm_sndpkt[i++] = (BYTE)tochar((chk >> 6) & 077);
krm_sndpkt[i++] = (BYTE)tochar(chk & 077);
break;
case 3:
chk3 = krm_chksum3(krm_sndpkt+1,0L);
krm_sndpkt[i++] = (BYTE)tochar((chk3 >> 12) & 017);
krm_sndpkt[i++] = (BYTE)tochar((chk3 >> 6) & 077);
krm_sndpkt[i++] = (BYTE)tochar(chk3 & 077);
break;
}
krm_sndpkt[i++] = krm_sndinit.eol;
krm_sndpkt[i] = NUL;
return (krmWriteComm(*krmcid, krm_sndpkt, i));
}
/*
* krm_chk1
*
* Perform a 1-byte check sum calculation on a value
*/
static WORD NEAR krm_chk1(WORD s)
{
return (((s & 192) >> 6) + s) & 63;
}
/*
* krm_chksum
*
* Perform a 2-byte check sum calculation on a string. The
* initial value of the checksum may be specified.
*/
static WORD NEAR krm_chksum(BYTE *p, WORD init)
{
WORD s;
for (s = init; *p != NUL; *p++)
s += *p;
return (s & 07777);
}
/*
* krm_chksum3
*
* Perform a 3-byte CRC checksum on a string. The initial
* value of the checksum may be specified.
*/
static DWORD NEAR krm_chksum3(BYTE *p, DWORD init)
{
DWORD crc = init;
WORD c, q;
while (c = *p++) {
q = (WORD)((crc ^ c) & 017);
crc = (crc >> 4) ^ (q * 010201);
q = (WORD)((crc ^ (c >> 4)) & 017);
crc = (crc >> 4) ^ (q * 010201);
}
return crc;
}
/*
* krm_ack
*
* Send an ack packet, possibly containing data
*/
void NEAR krm_ack(short len, BYTE * str)
{
krm_spack('Y', Kermit.seq, len, str);
krm_nxtpkt();
}
/*
* krm_nxtpkt
*
* Bump the packet sequence number
* and display the information if requested.
*/
static void NEAR krm_nxtpkt(void)
{
char buf[40];
Kermit.seq = (Kermit.seq + 1) & 63;
Kermit.packetcount += 1;
if (KermParams.verbose)
krmUpdateXferBox(IDD_KRM_PACKETS, ultoa(Kermit.packetcount, buf, 10));
if (IsIconic(Kermit.hWnd))
InvalidateRect(Kermit.hWnd, NULL, FALSE);
}
/*
* krm_rpar
*
* Prepare our parameters for transmission to
* the remote Kermit
*/
int NEAR krm_rpar(BYTE data[])
{
register int i = 0;
data[i++] = (BYTE)tochar(krm_rcvinit.maxpktsize);
data[i++] = (BYTE)tochar(krm_rcvinit.timeout);
data[i++] = (BYTE)tochar(krm_rcvinit.padcount);
data[i++] = (BYTE)ctl(krm_rcvinit.padchar);
data[i++] = (BYTE)tochar(krm_rcvinit.eol);
data[i++] = krm_rcvinit.quote;
data[i++] = krm_rcvinit.ebquote;
data[i++] = (BYTE)(Kermit.bctr + '0');
data[i++] = krm_rcvinit.rpquote;
data[i] = NUL;
return i;
}
/*
* krmSet8BitQuote
*
* Negotiate eight-bit quoting with remote Kermit
*/
static void NEAR krmSet8BitQuote(register BYTE sq)
{
krm_sndinit.ebquote = sq;
switch(sq) {
case 'N':
Kermit.ebqflag = FALSE;
break;
case 'Y':
if (krm_rcvinit.ebquote == KermParams.ebquote) {
krm_sndinit.ebquote = krm_rcvinit.ebquote;
Kermit.ebqflag = TRUE;
}
break;
default:
if (((sq > 32) && (sq < 63)) || ((sq > 95) && (sq < 127))) {
krm_rcvinit.ebquote = sq;
Kermit.ebqflag = TRUE;
}
else
Kermit.ebqflag = FALSE;
}
}
/*
* krm_spar
*
* Read remote Kermit's parameters and save them to
* a KRMSENDINIT structure to be used for forming outbound
* packets
*/
void NEAR krm_spar(BYTE *data, short len)
{
register int i;
register int x;
for (i = 0; i < len; i++) {
switch(i) {
case 0:
x = unchar(data[i]);
if ((x < KRM_MINPACKETSIZE) || (x > KRM_MAXPACKETSIZE))
x = KRM_DEFPACKETSIZE;
krm_sndinit.maxpktsize = x;
break;
case 1:
x = unchar(data[i]);
if ((x < KRM_MINTIMEOUT) || (x > KRM_MAXTIMEOUT))
x = KRM_DEFTIMEOUT;
krm_sndinit.timeout = x;
break;
case 2:
x = unchar(data[i]);
if (x > KRM_MAXPADCOUNT)
x = 0;
krm_sndinit.padcount = x;
break;
case 3:
x = ctl(data[i]);
krm_sndinit.padchar = (BYTE)x;
break;
case 4:
x = unchar(data[i]);
if ((x < 1) || (x > 31))
x = CR;
krm_sndinit.eol = (BYTE)x;
break;
case 5:
x = data[i];
x = ((x > 32 && x < 63) || (x > 95 && x < 127)) ? x : '#';
krm_sndinit.quote = (BYTE)x;
break;
case 6:
krmSet8BitQuote(data[i]);
break;
case 7:
x = data[i] - '0';
if ((x < 1) || (x > 3))
x = KRM_DEFBLOCKCHECK;
Kermit.bctr = x;
break;
case 8:
x = data[i];
if (Kermit.rptflag = ((x > 32 && x < 63) || (x > 95 && x < 127)))
krm_rcvinit.rpquote = krm_sndinit.rpquote = (BYTE)x;
break;
default:
return;
}
}
}
/*
* krmShowMessage
*
* Show a message according to a given string ID in the resource file
* or from a remote Kermit's error packet.
*/
void FAR krmShowMessage(int msgnum)
{
BYTE buf[KRM_MAXPACKETSIZE + 1];
BYTE appname[20];
int len = krm_rcvpkt.len;
if (msgnum == KRM_ERROR_PACKET)
krm_decode(buf, krm_rcvpkt.data, &len);
else
LoadString(Kermit.hInst, msgnum, (LPSTR)buf, sizeof(buf));
LoadString(Kermit.hInst, IDS_KRM_KERMIT, appname, sizeof(appname));
MessageBox(GetFocus(), buf, appname, MB_ICONASTERISK | MB_OK);
}
/*
* krmWndCommand
*
* Process WM_COMMAND message, returning FALSE if
* not handled, and TRUE otherwise.
* This routine should be placed in the terminal's
* WM_COMMAND processor before any other menu commands.
* If krmWndCommand returns FALSE, then the terminal
* should call its own WM_COMMAND routine.
*/
BOOL FAR krmWndCommand(HWND hWnd, WORD mode)
{
switch(mode) {
case IDM_KRM_RECEIVE:
Kermit.mode = mode;
Kermit.start = 'v';
wart();
break;
case IDM_KRM_SEND:
Kermit.mode = mode;
if (krmOpenDlgBox(hWnd, (FARPROC)krmSendFileProc, DT_KRM_SENDFILE)) {
Kermit.start = 's';
wart();
}
break;
case IDM_KRM_PROTOCOL:
krmOpenDlgBox(hWnd, (FARPROC)krmProtocol, DT_KRM_PROTOCOL);
break;
case IDM_KRM_PACKETS:
krmOpenDlgBox(hWnd, (FARPROC)krmPackets, DT_KRM_PACKETS);
break;
case IDM_KRM_FILEABORT:
Kermit.abort = KRM_FILEABORT;
break;
case IDM_KRM_BATCHABORT:
Kermit.abort = KRM_BATCHABORT;
break;
case IDM_KRM_ERRORABORT:
krm_errpkt(IDS_KRM_CANCELLED);
/* fall thru */
case IDM_KRM_CANCEL:
krmCreatePseudoPacket('E', PS_DONE, IDS_KRM_CANCELLED);
break;
default:
return FALSE;
}
return TRUE;
}
/*
* krm_errpkt
*
* Send an error packet to the remote Kermit according
* to the resource string ID requested.
*/
static void NEAR krm_errpkt(int msgnum)
{
char szMessage[80];
BYTE buf[KRM_MAXDATALEN + 1];
int inlen, outlen;
inlen = LoadString(Kermit.hInst, msgnum, (LPSTR)szMessage, sizeof(szMessage));
outlen = krm_encode(buf, szMessage, Kermit.maxsenddatalen, &inlen);
krm_spack('E', Kermit.seq, outlen, szMessage);
}
/*
* krmCreatePseudoPacket
*
* Handle an internal error as if an error packet were
* received from a remote Kermit
*/
void NEAR krmCreatePseudoPacket(char type, short state, int msgnum)
{
krm_rcvpkt.type = type;
krm_rcvpkt.state = state;
krm_rcvpkt.len = LoadString(Kermit.hInst, msgnum, krm_rcvpkt.data, sizeof(krm_rcvpkt.data));
}
/*
* krm_resend
*
* If krm_sndpkt is not empty, send it again.
* Otherwise, send a NAK
*/
void NEAR krm_resend(void)
{
char buf[40];
register int len = strlen(krm_sndpkt);
if (len)
krmWriteComm(*krmcid, krm_sndpkt, len);
else
krm_nak();
if (KermParams.verbose)
krmUpdateXferBox(IDD_KRM_RETRIES, itoa(Kermit.totalretries, buf, 10));
}
/*
* krmUpdateXferBox
*
* Update a field in the tranfer dialog box
*/
static void NEAR krmUpdateXferBox(WORD id, char *str)
{
if (IsWindow(Kermit.hWndXfer))
SetDlgItemText(Kermit.hWndXfer, id, str);
}
/*
* krm_nak
*
* Send a negative acknowledgment packet
*/
static void NEAR krm_nak()
{
krm_spack('N', Kermit.seq, 0, "");
}
/*
* krmOpenReceiveFile
*
* Open a file for writing and return its handle.
* If the file exists and file warning is on, then
* create a new name for it.
*/
static HANDLE NEAR krmOpenReceiveFile(BYTE *inbuf)
{
register int i, j;
char filename[13];
char ext[5];
int numresult;
char *ptrresult;
BOOL gotextension;
HANDLE hfile;
char tempname[9], genstring[20];
unsigned filecount;
memset(filename, NUL, 13);
ext[0] = NUL;
ptrresult = strtok(inbuf, "."); /* look for any extension */
numresult = strlen(ptrresult); /* find out how long */
numresult = numresult < 8 ? numresult : 8;
strncpy(filename,ptrresult,numresult); /* load up name */
gotextension = FALSE;
ptrresult = strtok(NULL, "."); /* get extension */
if (ptrresult != NULL) {
strcpy(ext,".");
strncat(ext, ptrresult,3);
ext[4] = NUL;
strcat(filename, ext);
gotextension = TRUE;
}
if (KermParams.FileWarning) {
for (filecount = 0; filecount < UINT_MAX; filecount++) {
if ((hfile = OpenFile((LPSTR)filename,
(OFSTRUCT FAR *)&Kermit.fstruct,OF_EXIST)) == -1)
break;
ptrresult = strtok(filename, ".");
strcpy(tempname, ptrresult);
numresult = strlen(ptrresult);
for (i = numresult; i < 8; i++)
tempname[i] = '0';
numresult = strlen(itoa(filecount + 1, genstring,10));
for (i = 8 - numresult, j = 0; i < 8; i++,j++)
tempname[i] = genstring[j];
tempname[8] = NUL;
strcpy(filename, tempname);
if (gotextension)
strcat(filename,ext);
}
}
hfile = OpenFile((LPSTR)filename,(OFSTRUCT FAR *)&Kermit.fstruct,OF_CREATE);
return (hfile);
}
/*
* krmWriteComm
*
* Write data to comm port. Add padding if required
*/
static short NEAR krmWriteComm(int cid, BYTE *buf, int len)
{
if (krm_sndinit.padcount) {
BYTE padbuf[KRM_MAXPADCOUNT];
memset(padbuf, krm_sndinit.padchar, krm_sndinit.padcount);
WriteComm(cid, padbuf, krm_sndinit.padcount);
}
return WriteComm(cid, buf, len);
}
/*
* krmHideChildren
*
* Child Windows enumeration call back function
*/
BOOL FAR PASCAL krmHideChildren(HWND hWnd, LONG lParam)
{
ShowWindow(hWnd, LOWORD(lParam));
return TRUE;
}
/*
* krmDoTimeout
*
* Timer call back function
*/
void FAR PASCAL krmDoTimeout(HWND hWnd,unsigned message,short event,DWORD time)
{
switch(event) {
case KRM_WAITPACKET:
if (KermParams.Bell)
MessageBeep(0);
krm_rcvpkt.state = PS_DONE;
krm_rcvpkt.type = 'T';
break;
case KRM_WAITSEND:
Kermit.delay = FALSE;
KillTimer(hWnd, event);
break;
default:
KillTimer(hWnd, event);
break;
}
}
/*
* krm_checkcnx
*
* Examine ack data packet for remote cancel command
*/
void NEAR krm_checkcnx()
{
if (krm_rcvpkt.len > 0) {
switch(krm_rcvpkt.data[0]) {
case 'X':
Kermit.abort = KRM_FILEABORT;
break;
case 'Z':
Kermit.abort = KRM_BATCHABORT;
break;
default:
Kermit.abort = 0;
}
}
}
/*
* krmPaint
*
* Draw the lower four bits of the packet count
* in the icon window if iconic
*/
void FAR krmPaint(HWND hWnd, HDC hDC)
{
char buf[20];
RECT rect;
GetClientRect(hWnd, &rect);
itoa(LOWORD(Kermit.packetcount), buf, 10),
DrawText(hDC, buf, -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
}
/*
* krm_savename
*
* Decode and display the name under which the file
* is saved on the remote Kermit
*/
void NEAR krm_savename()
{
BYTE buf[KRM_MAXPACKETSIZE + 1];
int len = krm_rcvpkt.len;
if (len > 0) {
krm_decode(buf, krm_rcvpkt.data, &len);
if (KermParams.verbose)
krmUpdateXferBox(IDD_KRM_SAVENAME, buf);
}
}
/*
* krmFlushQue
*
* Flush the communications port and the internal buffer
*/
void NEAR krmFlushQue()
{
FlushComm(*krmcid, 0); /* flush send and rececive comm driver queues */
FlushComm(*krmcid, 1);
*krmBuflen = 0; /* flush local buffer */
}